package strategies

import (
	"gitee.com/boxigg/strategy"
)

const (
	/*
	   """峰谷类型"""
	   // 根据窗口长度windows对价格峰谷的确认: 峰、谷间最小相隔windows个周期，称为周期峰谷，记为 WPV
	   """ 周期峰 WP 的定义
	   给定窗口长度 wnds,T-时刻的价格 P0 ,如果存在 x>=wnds,y>=wnds，
	   记：LL0=LLV(P[T-x,T]),HH0=HHV(P[T-x,T]),
	   LL1=LLV(P[T,T+y]), HH1=HHV(P[T,T+y]),
	   P0称为周期峰，满足：
	   1、P0=HHV(P[T-x,T+y]),
	   2、P[T-x]==LL0,P[T+y]==LL1
	   距离前后谷的周期数不小于 wnds
	   周期峰的确认：距离前期高点的周期数 intervals >=wnds 的最近低点(=HHV(price,intervals))
	   存在准确认的问题：即周期间隔==wnds时，价格不是最低价（指从近高开始）

	   	周期谷 WV 的定义

	   T-时刻的价格 P 称为周期谷，满足：
	   1、P=LLV(P[T-wnds,T+wnds])
	   2、距离前后峰的周期数不小于 wnds
	   """
	*/
	HH   = 1001  // 局部高（顶），给定周期内的最高点
	HHO  = 1002  // 局部高确认
	LL   = -1001 // 局部低（底），给定周期内的最低点
	LLO  = -1002 // 局部低确认
	WPI  = 11    // 峰
	QWPO = 13    // 仅周期数满足条件，此点不一定是局部底
	WPO  = 12    // 峰确认，周期数满足条件
	WVI  = -11   // 谷
	QWVO = -13   // 仅周期数满足条件
	WVO  = -12   // 谷确认
	// 基于周期数的峰谷
	// PVW = map[string]int{WPI:11,  // 峰
	//
	//			   WPO:12,  // 峰确认
	//			   WVI:-11,  // 谷
	//			   WVO:-12,  // 谷确认
	//	}
	//
	// 根据涨跌幅度 rng 对价格峰谷的确认：(p-v)/(p+v)*2*1000>= rng，称为价格峰谷，记为 PPV
	PPI = 101  // 价格峰 Price Peak Is
	PPO = 102  // 价格峰确认 Price Peak Ok
	PVI = -101 // 价格谷 Price Valley Is
	PVO = -102 // 价格谷确认 Price Valley Ok
	// PVR = map[string]int{PPI:101,  // 峰
	//
	//			   PPO:102,  // 峰确认
	//			   PVI:-101,  // 谷
	//			   PVO:-102,  // 谷确认
	//	}
	//
	// 根据窗口长度w和涨跌幅度r对价格的分类
	P   = 1  // 峰
	PO  = 2  // 峰确认
	QPO = 3  // 满足P的条件，但不是局部低, 前一标志是PPO，此时满足了周期间隔条件
	V   = -1 // 谷
	VO  = -2 // 谷确认
	QVO = -3 // 满足V的条件，但不是局部高

	HHH = 4  // 新高
	LLL = -4 // 新低

	UN = 0 // 未确认
)

var PVWR = map[string]int{
	"P":   1, // 峰
	"PO":  2, // 峰确认
	"QPO": 3,

	"V":   -1, // 谷
	"VO":  -2, // 谷确认
	"QVO": -3,
}

// 分形结构
type Fractal struct {
	HLFlag  int     //当前高低标志：当HHNo>LLNo时，=HH，当前属于高位；当HHNo<LLNo时，=LL，当前属于低位；=0时未确定
	PVFlag  int     //峰谷标志
	TPVFlag int     //基于时间（周期）的峰谷标志
	PPVFlag int     //基于价格的峰谷标志
	PVPrice float64 //峰谷值
	No      int     //原始数据序号
	HHPrice float64 //局部最高价
	HHNo    int     //局部最高价在原始数据中的序号
	LLPrice float64 //局部最低价
	LLNo    int     //局部最低价在原始数据中的序号
}

// 分形序列
type Fractals struct {
	s                                  []*Fractal // fractal series
	count                              int        // 不同分形发现时的数据
	cur                                *Fractal   // 当前分形
	odl                                int        // 原始数据长度
	winds                              int        // 窗口长度
	rng                                float64    //峰谷间最小相对长度（千分比）
	hh0, ll0, last_price, xprice       float64    //当前的最高价，最低价，最新价，与cur_flag 对应的价格
	p_hh0, p_ll0, pl0, cur_flag, xposi int        //当前的最高价，最低价，最新价 的位置，cur_flag，xposi：当前标志及对应的位置

}

func NewFractals() *Fractals {
	f := new(Fractals)
	f.s = make([]*Fractal, 0)
	f.odl = 0
	f.count = 0
	f.cur = new(Fractal)
	f.winds = 120
	f.rng = 2

	return f
}

func (f *Fractals) OnTickFractal(last_price float64) {
	f.odl += 1
	f.last_price = last_price
	hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi := clcPV(f.hh0, f.ll0, last_price, f.xprice, f.p_hh0, f.p_ll0, f.pl0, f.cur_flag, f.xposi, f.rng, f.winds)
	if cur_flag != f.cur_flag {
		nf := new(Fractal)
		nf.HHNo = p_hh0
		nf.LLNo = p_ll0
		nf.No = f.odl
		nf.HHPrice = hh0
		nf.LLPrice = ll0
		if cur_flag > 0 {
			nf.HLFlag = HH
		} else {
			nf.HLFlag = LL
		}
		f.s = append(f.s, nf)
	}
	f.hh0, f.ll0, f.p_hh0, f.p_ll0, f.cur_flag, f.xprice, f.xposi = hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi

}
func clcPV(hh0, ll0, last_price, xprice float64, p_hh0, p_ll0, pl0, cur_flag, xposi int, rng float64, wnds int) (float64, float64, int, int, int, float64, int) {
	if cur_flag == QWPO { // # 当前是周期峰,要确认周期谷
		if last_price < ll0 { // # new low
			if (xprice-last_price)*2/(xprice+last_price)*1000 >= rng { // # 相对距离满足峰的定义
				return last_price, last_price, pl0, pl0, PO, xprice, xposi
			} else { // # 准周期峰转变为周期峰
				return last_price, last_price, pl0, pl0, WPO, xprice, xposi
			}
		} else if last_price > hh0 { // # new high
			if (last_price-ll0)*2/(ll0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
				if pl0-p_ll0 < wnds {
					return last_price, last_price, pl0, pl0, PVO, ll0, p_ll0
				} else {
					return last_price, last_price, pl0, pl0, VO, ll0, p_ll0
				}
			} else {
				if pl0-p_ll0 < wnds {
					return last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposi
				} else { // # periods valley
					return last_price, last_price, pl0, pl0, WVO, ll0, p_ll0
				}
			}
		} else {
			if pl0-p_ll0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWVO, ll0, p_ll0
			}
		}
	} else if cur_flag == WPO { // # 当前是周期峰,要确认周期谷
		if last_price < ll0 { // # new low
			if (xprice-last_price)*2/(xprice+last_price)*1000 >= rng { // # 相对距离满足峰的定义
				return last_price, last_price, pl0, pl0, PO, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, cur_flag, xprice, xposi
			}
		} else if last_price > hh0 { // # new high
			if (last_price-ll0)*2/(ll0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
				if pl0-p_ll0 < wnds {
					return last_price, last_price, pl0, pl0, PVO, ll0, p_ll0
				} else {
					return last_price, last_price, pl0, pl0, VO, ll0, p_ll0
				}
			} else {
				if pl0-p_ll0 < wnds {
					return last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposi
				} else { // # periods valley
					return last_price, last_price, pl0, pl0, WVO, ll0, p_ll0
				}
			}
		} else {
			if pl0-p_ll0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWVO, ll0, p_ll0
			}
		}
	} else if cur_flag == QWVO { // # 当前是周期峰,要确认周期谷
		if last_price > hh0 { // # new low
			if (-xprice+last_price)*2/(xprice+last_price)*1000 >= rng { // # 相对距离满足峰的定义
				return last_price, last_price, pl0, pl0, VO, xprice, xposi
			} else { // # 准周期转变为周期
				return last_price, last_price, pl0, pl0, WVO, xprice, xposi
			}

		} else if last_price < ll0 { // # new high
			if (hh0-last_price)*2/(hh0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
				if pl0-p_hh0 < wnds {
					return last_price, last_price, pl0, pl0, PPO, hh0, p_hh0
				} else {
					return last_price, last_price, pl0, pl0, PO, hh0, p_hh0
				}
			} else {
				if pl0-p_hh0 < wnds {
					return hh0, last_price, p_hh0, pl0, cur_flag, xprice, xposi
				} else { // # periods valley
					return last_price, last_price, pl0, pl0, WPO, hh0, p_hh0
				}
			}
		} else {
			if pl0-p_hh0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWPO, hh0, p_hh0
			}
		}
	} else if cur_flag == WVO { // # 当前是周期谷,要确认周期峰
		if last_price > hh0 { // # new high
			if (-xprice+last_price)*2/(xprice+last_price)*1000 >= rng { // # 相对距离满足峰的定义
				return last_price, last_price, pl0, pl0, VO, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, cur_flag, xprice, xposi
			}
		} else if last_price < ll0 { // # new low
			if (hh0-last_price)*2/(hh0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
				if pl0-p_hh0 < wnds {
					return last_price, last_price, pl0, pl0, PPO, hh0, p_hh0
				} else {
					return last_price, last_price, pl0, pl0, PO, hh0, p_hh0
				}
			} else {
				if pl0-p_ll0 < wnds {
					return last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposi
				} else { // # periods valley
					return last_price, last_price, pl0, pl0, WPO, hh0, p_hh0
				}
			}
		} else {
			if pl0-p_hh0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWPO, hh0, p_hh0
			}
		}
	} else if cur_flag == PPO { // # 当前是价格峰,要确认谷
		if pl0-xposi < wnds {
			if last_price < ll0 { // # 创新低
				return last_price, last_price, pl0, pl0, cur_flag, xprice, xposi
			} else if last_price > hh0 {
				if (last_price-ll0)*2/(ll0+last_price)*1000 >= rng { // # 相对距离满足峰的定义
					return last_price, last_price, pl0, pl0, PVO, ll0, p_ll0
				} else {
					return last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposi
				}
			} else {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			}
		} else {
			// # print(hh0, last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposition)
			if last_price < ll0 { // # 创新低
				return last_price, last_price, pl0, pl0, PO, xprice, xposi
			} else if last_price > hh0 { // # 谷被确认
				if (last_price-ll0)*2/(ll0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
					if pl0-p_ll0 < wnds {
						return last_price, last_price, pl0, pl0, PVO, ll0, p_ll0
					} else {
						return last_price, last_price, pl0, pl0, VO, ll0, p_ll0
					}
				} else {
					if pl0-p_ll0 < wnds {
						return last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposi
					} else { // # periods valley
						return last_price, last_price, pl0, pl0, WVO, ll0, p_ll0
					}
				}
			} else {
				return hh0, ll0, p_hh0, p_ll0, QPO, xprice, xposi
			}
		}
	} else if cur_flag == QPO { // # 当前是价格峰,要确认谷
		//  # print(hh0, last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposition)
		if last_price < ll0 { // # 创新低
			return last_price, last_price, pl0, pl0, PO, xprice, xposi
		} else if last_price > hh0 {
			if (last_price-ll0)*2/(ll0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
				if pl0-p_ll0 < wnds {
					return last_price, last_price, pl0, pl0, PVO, ll0, p_ll0
				} else {
					return last_price, last_price, pl0, pl0, VO, ll0, p_ll0
				}
			} else {
				if pl0-p_ll0 < wnds {
					return last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposi
				} else { // # periods valley
					return last_price, last_price, pl0, pl0, WVO, ll0, p_ll0
				}
			}
		} else {
			if pl0-p_ll0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWVO, ll0, p_ll0
			}
		}
	} else if cur_flag == PVO { // # 当前是价格谷,要确认
		if pl0-xposi < wnds {
			if last_price > hh0 { // # 创新高
				return last_price, last_price, pl0, pl0, cur_flag, xprice, xposi
			} else if last_price < ll0 {
				if (hh0-last_price)*2/(hh0+last_price)*1000 >= rng { // # 相对距离满足峰的定义
					return last_price, last_price, pl0, pl0, PPO, hh0, p_hh0
				} else {
					return hh0, last_price, p_hh0, pl0, cur_flag, xprice, xposi
				}
			} else {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			}
		} else {
			if last_price > hh0 { // # 创新高
				return last_price, last_price, pl0, pl0, VO, xprice, xposi
			} else if last_price < ll0 { // # 谷被确认
				if (hh0-last_price)*2/(hh0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
					if pl0-p_ll0 < wnds {
						return last_price, last_price, pl0, pl0, PPO, hh0, p_hh0
					} else {
						return last_price, last_price, pl0, pl0, PO, hh0, p_hh0
					}
				} else {
					if pl0-p_hh0 < wnds {
						return hh0, last_price, p_hh0, pl0, cur_flag, xprice, xposi
					} else { // # periods valley
						return last_price, last_price, pl0, pl0, WPO, hh0, p_hh0
					}
				}
			} else {
				return hh0, ll0, p_hh0, p_ll0, QVO, xprice, xposi
			}
		}
	} else if cur_flag == QVO { // # 当前是价格峰,要确认谷
		// # print(hh0, last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposition)
		if last_price > hh0 { // # 创新高
			return last_price, last_price, pl0, pl0, VO, xprice, xposi
		} else if last_price < ll0 { // # 创新低
			if (hh0-last_price)*2/(hh0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
				if pl0-p_hh0 < wnds {
					return last_price, last_price, pl0, pl0, PPO, hh0, p_hh0
				} else {
					return last_price, last_price, pl0, pl0, PO, hh0, p_hh0
				}
			} else {
				if pl0-p_hh0 < wnds {
					return hh0, last_price, p_hh0, pl0, cur_flag, xprice, xposi
				} else { // # periods peak
					return last_price, last_price, pl0, pl0, WPO, hh0, p_hh0
				}
			}
		} else {
			if pl0-p_hh0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWPO, hh0, p_hh0
			}
		}
	} else if cur_flag == PO { // # 当前是峰,要确认谷
		if last_price < ll0 { // # 创新低
			return last_price, last_price, pl0, pl0, cur_flag, xprice, xposi
		} else if last_price > hh0 {
			if (last_price-ll0)*2/(ll0+last_price)*1000 >= rng { // # 相对距离满足峰的定义
				if pl0-p_ll0 < wnds {
					return last_price, last_price, pl0, pl0, PVO, ll0, p_ll0
				} else {
					return last_price, last_price, pl0, pl0, VO, ll0, p_ll0
				}
			} else {
				if pl0-p_ll0 < wnds {
					return last_price, ll0, pl0, p_ll0, cur_flag, xprice, xposi
				} else { // # periods valley
					return last_price, last_price, pl0, pl0, WVO, ll0, p_ll0
				}
			}
		} else {
			if pl0-p_ll0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWVO, ll0, p_ll0
			}
		}
	} else if cur_flag == VO { // # 当前是谷,要确认峰
		if last_price > hh0 { // # 创新高
			return last_price, last_price, pl0, pl0, cur_flag, xprice, xposi
		} else if last_price < ll0 {
			if (hh0-last_price)*2/(hh0+last_price)*1000 >= rng { // # 相对距离满足谷的定义
				if pl0-p_hh0 < wnds {
					return last_price, last_price, pl0, pl0, PPO, hh0, p_hh0
				} else {
					return last_price, last_price, pl0, pl0, PO, hh0, p_hh0
				}
			} else {
				if pl0-p_hh0 < wnds {
					return hh0, last_price, p_hh0, pl0, cur_flag, xprice, xposi
				} else { // # periods peak
					return last_price, last_price, pl0, pl0, WPO, hh0, p_hh0
				}
			}
		} else {
			if pl0-p_hh0 < wnds {
				return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
			} else {
				return last_price, last_price, pl0, pl0, QWPO, hh0, p_hh0
			}
		}
	} else if cur_flag == LLL { // # 最新是低
		if last_price < ll0 { // # 可能的结果：价格峰被确认、峰被确认、周期峰被确认、不变
			if pl0-p_hh0 < wnds {
				if (hh0-last_price)*2*1000/(last_price+hh0) > rng { // # 价格峰被确认
					return hh0, ll0, pl0, p_ll0, PPO, hh0, p_hh0
				} else {
					return hh0, last_price, p_hh0, pl0, cur_flag, xprice, xposi
				}
			} else if (hh0-last_price)*2*1000/(last_price+hh0) > rng { // # 峰被确认
				return last_price, ll0, pl0, p_ll0, PO, hh0, p_hh0
			} else { // # 周期峰被确认
				return hh0, last_price, p_hh0, pl0, WPO, hh0, p_hh0
			}

		} else if last_price >= hh0 { // # 创新高
			if pl0-p_ll0 < wnds {
				if (last_price-ll0)*2*1000/(last_price+ll0) > rng { // # 距离谷被确认
					return last_price, ll0, pl0, p_ll0, PVO, ll0, p_ll0
				} else {
					return last_price, ll0, pl0, p_ll0, HHH, last_price, pl0
				}
			} else if (last_price-ll0)*2*1000/(last_price+ll0) > rng { // # 谷被确认
				return last_price, ll0, pl0, p_ll0, VO, ll0, p_ll0
			} else { // # 周期谷被确认
				return last_price, ll0, pl0, p_ll0, WVO, ll0, p_ll0
			}
		} else if pl0-p_ll0 >= wnds { // # 周期谷被确认
			return last_price, ll0, pl0, p_ll0, WVO, ll0, p_ll0
		} else {
			return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
		}
	} else if cur_flag == HHH {
		if last_price < ll0 { // # 创新低
			if pl0-p_hh0 < wnds {
				if (xprice-last_price)*2*1000/(last_price+xprice) > rng { // # 价格峰被确认
					return last_price, ll0, pl0, p_ll0, PPO, xprice, xposi
				} else if ll0 > xprice {
					return hh0, last_price, p_hh0, pl0, LLL, last_price, pl0
				} else {
					return hh0, ll0, p_hh0, p_ll0, cur_flag, last_price, pl0
				}
			} else if (hh0-last_price)*2*1000/(last_price+hh0) > rng { // # 峰被确认
				return last_price, ll0, pl0, p_ll0, PO, hh0, p_hh0
			} else { // # 周期峰被确认
				if ll0 < last_price {
					ll0 = last_price
					p_ll0 = pl0
				}
				return hh0, ll0, p_hh0, p_ll0, WPO, hh0, p_hh0
			}
		} else if last_price > hh0 { // # 创新高
			if pl0-p_ll0 < wnds {
				if (last_price-ll0)*2*1000/(last_price+ll0) > rng { // # 距离谷被确认
					return last_price, last_price, pl0, pl0, PVO, ll0, p_ll0
				} else {
					return last_price, ll0, pl0, p_ll0, cur_flag, last_price, pl0
				}

			} else if (last_price-ll0)*2*1000/(last_price+ll0) > rng { // # 谷被确认
				return last_price, last_price, pl0, pl0, VO, ll0, p_ll0
			} else { // # 周期谷被确认
				return last_price, last_price, pl0, pl0, WVO, ll0, p_ll0
			}
		} else if pl0-p_ll0 >= wnds { // # 准周期谷被确认
			return hh0, ll0, p_hh0, p_ll0, QWVO, ll0, p_ll0

		} else {
			return hh0, ll0, p_hh0, p_ll0, cur_flag, xprice, xposi
		}
	} else { // # cur_pv_flag==UN
		if last_price >= hh0 {
			return last_price, ll0, pl0, p_ll0, HHH, last_price, pl0
		} else {
			return hh0, last_price, p_hh0, pl0, LLL, last_price, pl0
		}
	}
	// return hh0, last_price, p_hh0, pl0, LLL, last_price, pl0

}

// 基于分形的策略
type StraFractal struct {
	*strategy.StraBase
	timeClass  int
	priceClass float64
	pctClass   float64
	*Fractals
}
